#ifndef GAME_H
#define GAME_H
#include "game_platform.h"
#include "game_sim_region.h"
#include "game_asset.h"
#include "game_random.h"
#include "game_cutscene.h"
#include "game_world_mode.h"
#include "game_memory.h"
#include "game_render.h"

#define DLIST_INSERT(Sentinel, Element) \
    (Element)->Next = (Sentinel)->Next; \
    (Element)->Prev = (Sentinel);       \
    (Element)->Next->Prev = (Element);  \
    (Element)->Prev->Next = (Element);

#define DLIST_INSERT_AT_LAST(Sentinel, Element) \
    (Element)->Next = (Sentinel);               \
    (Element)->Prev = (Sentinel)->Prev;         \
    (Element)->Next->Prev = (Element);          \
    (Element)->Prev->Next = (Element);

#define DLIST_INIT(Sentinel)       \
    (Sentinel)->Next = (Sentinel); \
    (Sentinel)->Prev = (Sentinel);

#define FREELIST_ALLOC(Result, FreeListPointer, AllocationCode) \
    if (((Result) = (FreeListPointer))) {                       \
        FreeListPointer = (Result)->NextFree;                   \
    } else {                                                    \
        Result = AllocationCode;                                \
    }

#define FREELIST_DEALLOCATE(Pointer, FreeListPointer) \
    if (Pointer) {                                    \
        (Pointer)->NextFree = (FreeListPointer);      \
        (FreeListPointer) = (Pointer);                \
    }

// 宏定义：计算两个值中的最小值
// 如果 A 小于 B，则返回 A；否则返回 B
#define Minimum(A, B) ((A < B) ? (A) : (B))

// 宏定义：计算两个值中的最大值
// 如果 A 大于 B，则返回 A；否则返回 B
#define Maximum(A, B) ((A > B) ? (A) : (B))

// 注意: 平台层为游戏提供的服务
// 注意: 游戏为平台玩家提供的服务
// （这个部分未来可能扩展——例如声音处理可能在单独的线程中）

// 四个主要功能 - 时间管理，控制器/键盘输入，位图缓冲区，声音缓冲区

struct game_offscreen_buffer {
    // TODO（casey）：未来，渲染将特别变成一个三层抽象！！！
    void *Memory;
    // 后备缓冲区的宽度和高度
    int Width;
    int Height;
    int Pitch;
};

struct game_sound_output_buffer {
    int SamplesPerSecond;  // 采样率：每秒采样48000次
    int SampleCount;
    int16 *Samples;
};

// 游戏按钮状态结构体
struct game_button_state {
    int HalfTransitionCount;  // 按钮状态变化的次数（用于处理按钮的按下和释放事件）
    bool32 EndedDown;  // 按钮是否处于按下状态（true 表示按下，false 表示释放）
};

// 游戏控制器输入结构体
struct game_controller_input {
    bool32 IsConnected;  // 控制器是否已连接
    bool32 IsAnalog;  // 控制器是否为模拟输入（例如操控杆，判断是否为连续输入）

    real32 StickAverageX;  // 左摇杆 X 轴的平均值
    real32 StickAverageY;  // 左摇杆 Y 轴的平均值

    // 按钮状态的联合体，用于存储按钮输入信息
    union {
        game_button_state Buttons[12];  // 按钮状态数组，最多支持 12 个按钮

        // 通过命名字段表示常见的控制按钮（用于便捷访问）
        struct {
            game_button_state MoveUp;     // 上移按钮
            game_button_state MoveDown;   // 下移按钮
            game_button_state MoveLeft;   // 左移按钮
            game_button_state MoveRight;  // 右移按钮

            game_button_state ActionUp;     // 动作上按钮
            game_button_state ActionDown;   // 动作下按钮
            game_button_state ActionLeft;   // 动作左按钮
            game_button_state ActionRight;  // 动作右按钮

            game_button_state LeftShoulder;   // 左肩键状态
            game_button_state RightShoulder;  // 右肩键状态

            game_button_state Back;   // 返回按钮
            game_button_state Start;  // 启动按钮

            ////////////////////添加按钮再之前添加////////////////////
            game_button_state Terminator;  // 占位符号
        };
    };
};

enum game_input_mouse_button {
    PlatformMouseButton_Left,
    PlatformMouseButton_Middle,
    PlatformMouseButton_Right,
    PlatformMouseButton_Extended0,
    PlatformMouseButton_Extended1,

    PlatformMouseButton_Count,
};

struct game_render_commands {
    uint32 Width;
    uint32 Height;

    uint32 SortEntryCount;
    uint32 MaxPushBufferSize;  // PushBuffer的最大允许大小（单位：字节）
    uint8 *PushBufferDataAt;   // PushBuffer的起始地址，用于存储渲染数据
    uint8 *PushBufferBase;

    v4 ClearColor;

    uint32 LastUsedManualSortkey;

    uint32 ClipRectCount;
    uint32 MaxRenderTargetIndex;
    struct render_entry_cliprect *FirstRect;
    struct render_entry_cliprect *LastRect;
};

#define RenderCommandStruct(MaxPushBufferSizeInit, PushBufferInit, WidthInit, HeightInit) \
    {.Width = WidthInit,                                                                  \
     .Height = HeightInit,                                                                \
     .SortEntryCount = 0,                                                                 \
     .MaxPushBufferSize = MaxPushBufferSizeInit,                                          \
     .PushBufferDataAt = ((uint8 *)PushBufferInit) + MaxPushBufferSizeInit,               \
     .PushBufferBase = (uint8 *)PushBufferInit,                                           \
     .ClearColor = {0, 0, 0, 0},                                                          \
     .ClipRectCount = 0,                                                                  \
     .FirstRect = 0,                                                                      \
     .LastRect = 0};
// 游戏输入结构体（包含多个控制器的输入信息）
struct game_input {
    game_button_state MouseButtons[PlatformMouseButton_Count];
    // 存储鼠标按键的状态，数组包含五个元素，分别代表鼠标的五个按钮（如左键、右键、中键等）
    bool32 ShiftDown, AltDown, ControlDown;

    uint32 MouseButton;
    // 当前被按下的鼠标按钮，通常用一个整数表示，值为按钮的编号（例如：1
    // 为左键，2 为右键）

    // 每一帧的时间增量，表示从上一帧到当前帧所经过的时间（通常单位为秒）
    real32 dtForFrame;

    real32 MouseX, MouseY, MouseZ;
    // 存储鼠标光标的当前位置：
    // - MouseX：鼠标在屏幕上的 X 坐标（水平位置）
    // - MouseY：鼠标在屏幕上的 Y 坐标（垂直位置）
    // -
    // MouseZ：鼠标滚轮的当前状态（用于表示鼠标滚轮的滚动程度，通常为一个整数，
    // 正数表示向前滚动，负数表示向后滚动）

    // SecondsToAdvanceOverUpdate: 计算每一帧更新时游戏状态应该前进的秒数
    // 这个值通常是基于目标帧率或时间步进计算得出的，用于确保游戏能以一致的速度更新，即使帧率发生变化。
    // 它用于控制游戏更新逻辑中时间的流逝，确保无论系统的帧率如何，游戏都能按照预期进展。
    real32 SecondsToAdvanceOverUpdate;

    game_controller_input Controllers[MAX_CONTROLLER_COUNT];  // 最多支持 4 个控制器
    bool32 QuitRequested;
};

inline bool32 IsDown(game_button_state State) {
    bool32 Result = (State.EndedDown);

    return (Result);
}

inline bool32 WasPressed(game_button_state State) {
    bool32 Result = ((State.HalfTransitionCount > 1) ||
                     ((State.HalfTransitionCount == 1) && (State.EndedDown)));
    return Result;
}

// 获取指定索引的控制器输入
inline game_controller_input *GetController(game_input *Input, uint32 ControllerIndex) {
    // 确保传入的控制器索引在有效范围内
    Assert(ControllerIndex < ArrayCount(Input->Controllers));

    // 获取指定索引的控制器输入，并将其返回
    game_controller_input *Result = &Input->Controllers[ControllerIndex];

    return Result;  // 返回对应的控制器输入结构体指针
}

// 宏定义：定义游戏更新和渲染函数的通用签名
// 它接受三个参数：游戏内存、游戏输入和屏幕缓冲区
#define GAME_UPDATE_AND_RENDER(name) \
    void name(game_memory *Memory, game_input *Input, game_render_commands *RenderCommands)

// 为更新和渲染函数定义一个类型，方便函数指针的声明和使用
typedef GAME_UPDATE_AND_RENDER(game_update_and_render);

// 宏定义：定义获取音频采样函数的通用签名
// 它接受两个参数：游戏内存和音频输出缓冲区
#define GAME_GET_SOUND_SAMPLES(name) \
    void name(game_memory *Memory, game_sound_output_buffer *SoundBuffer)

// 为获取音频采样函数定义一个类型，方便函数指针的声明和使用
typedef GAME_GET_SOUND_SAMPLES(game_get_sound_samples);

// 游戏更新和渲染的主函数
// 参数包含图像缓冲区和音频缓冲区
void GameUpdateAndRender(game_memory *Memory,  //
                         game_input *Input,    //
                         game_offscreen_buffer *Buffer);
void GameGetSoundSamples(game_memory *Memory,  //
                         game_sound_output_buffer *Bufferr);
// 三个主要功能：
// 1. 时间管理（Timing）
// 2. 控制器/键盘输入（Controller/Keyboard Input）
// 3. 位图输出（Bitmap Output）和声音（Sound）
// 使用的缓冲区（Buffer）

#include "game_world.h"
#include "game_audio.h"

inline arena_push_params Align(uint32 Alignment, bool32 Clear) {
    arena_push_params Params = DefaultArenaParams();
    if (Clear) {
        Params.Flags |= ArenaFlag_ClearToZero;
    } else {
        Params.Flags &= ~ArenaFlag_ClearToZero;
    }
    Params.Alignment = Alignment;
    return (Params);
}

inline arena_push_params NoClear(void) {
    arena_push_params Params = DefaultArenaParams();
    Params.Flags &= ~ArenaFlag_ClearToZero;
    return (Params);
}

inline arena_push_params AlignNoClear(uint32 Alignment) {
    arena_push_params Params;
    Params.Flags = 0;
    Params.Alignment = Alignment;
    return Params;
}

inline memory_index GetArenaSizeRemaining(memory_arena *Arena,
                                          arena_push_params Params = DefaultArenaParams()) {
    memory_index Result = Arena->Size - (Arena->Used + GetAlignmentOffset(Arena, Params));
    return Result;
}

struct environment_map {
    loaded_bitmap LOD[4];
    // Pz表示当前物体在Z轴上的位置，计算时会基于原点Z值（OriginZ）加上Z差异（ZDiff）。
    // 它表示物体在3D空间中的垂直位置，可以用来判断物体与地图的相对高度。
    real32 Pz;
};

inline world_position CenteredChunkPoint(uint32 ChunkX, uint32 ChunkY, uint32 ChunkZ) {
    world_position Result = {};  // 初始化一个新的 world_position 结构体，所有成员都置为默认值

    Result.ChunkX = ChunkX;  // 设置绝对瓦片 X 坐标
    Result.ChunkY = ChunkY;  // 设置绝对瓦片 Y 坐标
    Result.ChunkZ = ChunkZ;  // 设置绝对瓦片 Z 坐标

    return Result;  // 返回创建的 world_position 结构体
}

// 内联函数，用于计算给定块（Chunk）的中心世界坐标
inline world_position CenteredChunkPoint(world_chunk *Chunk) {
    // 调用 CenteredChunkPoint 函数，传入块的 X、Y 和 Z 坐标，计算该块的中心世界坐标
    world_position Result = CenteredChunkPoint(Chunk->ChunkX, Chunk->ChunkY, Chunk->ChunkZ);

    // 返回计算出的世界坐标
    return Result;
}

// Subtract 函数计算两个瓦片位置之间的差异
// TileMap 是瓦片地图，A 和 B 是两个瓦片位置
inline v3 Subtract(world *World, world_position *A, world_position *B) {
    // 计算瓦片位置的x、y、z轴差异
    v3 dTile = {(real32)A->ChunkX - (real32)B->ChunkX,   // x轴差异
                (real32)A->ChunkY - (real32)B->ChunkY,   // y轴差异
                (real32)A->ChunkZ - (real32)B->ChunkZ};  // z轴差异

    // 计算实际的距离差异（以米为单位）
    v3 Result = Hadamard(World->ChunkDimInMeters, dTile) + (A->Offset_ - B->Offset_);

    // 返回计算后的瓦片位置差异
    return Result;
}

#define HIT_POINT_SUB_COUNT 4

// 低实体块引用（low_entity_chunk_reference）结构体：
// 用于间接引用存储在瓦片块中的低实体。
// 每个引用包含以下两部分：
struct low_entity_chunk_reference {
    world_chunk *TileChunk;  // 表示实体所在的瓦片块（Tile Chunk）的索引或 ID。
    uint32 EntityIndexInChunk;  // 表示实体在该瓦片块中的索引，用于定位具体的实体。
};

struct controlled_hero {
    real32 RecenterTimer;
    brain_id BrainID;
    v2 ddP;
};

// 定义配对碰撞规则标志，用于标识碰撞规则的不同特性
enum pairwise_collision_rule_flag {
    // 表示碰撞应该发生的标志位
    PairCollisionFlag_CanCollide = 0x1,  // 该标志位设置为1表示实体之间应发生碰撞

    // 表示临时碰撞规则的标志位
    PairCollisionFlag_Temporary = 0x2,  // 该标志位设置为1表示碰撞规则是临时的，仅在特定条件下有效
};

struct ground_buffer {
    // world_position: 存储地面在世界坐标中的位置，
    // 用于计算实体相对于地面的偏移量。
    world_position P;

    loaded_bitmap Bitmap;
};

enum game_mode {
    GameMode_None,
    GameMode_TitleScreen,
    GameMode_CutScene,
    GameMode_World,
};

// 游戏状态结构体，包含玩家的当前状态信息和与世界相关的内存
struct game_state {
    real32 tSine;
    bool32 IsInitialized;

    memory_arena ModeArena;  // 专门用于存储世界相关数据的内存池
    memory_arena AudioArena;

    // 为每个控制器分配一个玩家索引
    controlled_hero ControledHeroes[MAX_CONTROLLER_COUNT];

    // 预加载的纹理，用于表示光照贴图（漫反射）
    loaded_bitmap TestDiffuse;

    // 预加载的纹理，用于表示法线贴图
    loaded_bitmap TestNormal;
    audio_state AudioState;
    playing_sound *Music;
    game_mode GameMode;
    union {
        // game_mode_world *World;
        game_mode_title_screen *TitleScreen;
        game_mode_cutscene *Cutscene;
        game_mode_world *WorldMode;
    };
};

struct game_assets;
// 结构体用于表示临时状态信息
struct transient_state {
    platform_work_queue *LowPriorityQueue;

    bool32 Initialized;

    // 临时内存分配器，用于存储非持久数据
    memory_arena TransientArena;

    // 环境贴图的宽度
    uint32 EnvMapWidth;

    // 环境贴图的高度
    uint32 EnvMapHeight;

    environment_map EnvMaps[3];
    task_with_memory Tasks[4];
    game_assets *Assets;
    uint32 MainGenerationID;
};

inline void *Copy(memory_index Size, void *SourceInit, void *DestInit) {
    uint8 *Source = (uint8 *)SourceInit;
    uint8 *Dest = (uint8 *)DestInit;
    while (Size--) {
        *Dest++ = *Source++;
    }
    return DestInit;
}
internal world *CreateWorld(v3 ChunkDimInMeters, memory_arena *ParentArena) {
    world *World = PushStruct(ParentArena, world);
    World->ChunkDimInMeters = ChunkDimInMeters;
    World->FirstFree = 0;
    SubArena(&World->Arena, ParentArena, GetArenaSizeRemaining(ParentArena), NoClear());
    return World;
}

inline bool32 StringsAreEqual(const char *A, const char *B) {
    bool32 Result = (A == B);
    if (A && B) {
        while (*A && *B && (*A == *B)) {
            ++A;
            ++B;
        }
        Result = ((*A == 0) && (*B == 0));
    }
    return Result;
}

inline bool32 StringsAreEqual(uintptr_t ALength, const char *A, const char *B) {
    bool32 Result = false;
    if (B) {
        const char *At = B;
        for (uintptr_t Index = 0; Index < ALength; ++Index, ++At) {
            if ((*At == 0) || (A[Index] != *At)) {
                return false;
            }
        }
        Result = (*At == 0);
    } else {
        Result = (ALength == 0);
    }
    return Result;
}

inline bool IsEndOfLine(char C) {
    bool Result = (C == '\n') || (C == '\r');
    return Result;
}

inline bool IsWhitespace(char C) {
    bool Result = ((C == ' ') || (C == '\t') || (C == '\v') || (C == '\f') || IsEndOfLine(C));
    return Result;
}
inline bool32 StringsAreEqual(memory_index ALength, const char *A, memory_index BLength,
                              const char *B) {
    bool32 Result = (ALength == BLength);
    if (Result) {
        Result = true;
        for (uint32 Index = 0; Index < ALength; ++Index) {
            if (A[Index] != B[Index]) {
                Result = false;
                break;
            }
        }
    }
    return Result;
}

extern platform_api Platform;
#define DEFUALT_MEMORY_ALIGNMENT 4
#define GroundBufferWidth 256
#define GroundBufferHeight 256

void LoadBitmap(game_assets *Assets, bitmap_id ID, bool32 Immediate);
void LoadSound(game_assets *Assets, sound_id ID);
task_with_memory *BeginTaskWithMemory(transient_state *TranState, bool32 DependsOnGameMode);
void EndTaskWithMemory(task_with_memory *Task);
asset_memory_block *InsertBlock(asset_memory_block *Prev, memory_index Size, void *Memory);
game_assets *DebugGetGameAssets(game_memory *Memory);
memory_index GetEffectiveSizeFor(memory_arena *Arena, memory_index SizeInit,
                                 arena_push_params Params = DefaultArenaParams());
bool32 ArenaHasRoomFor(memory_arena *Arena, memory_index SizeInit,
                       arena_push_params Params = DefaultArenaParams());
void SetGameMode(game_state *GameState, transient_state *TranState, game_mode GameMode);
bitmap_id GetRandomBitmapFrom(game_assets *Assets, assets_type_id TypeID, random_series *Series);
sound_id GetRandomSoundFrom(game_assets *Assets, assets_type_id TypeID, random_series *Series);
loaded_bitmap MakeNothingsTest(memory_arena *Arena);
uint32 DEBUGGetMainGenerationID(game_memory *Memory);
char *PushString(memory_arena *Arena, const char *Source);
char *PushAndNullTerminate(memory_arena *Arena, uint32 Length, const char *Source);
#endif